package cn.spike.rockcc.service.impl;

import cn.spike.rockcc.domain.*;
import cn.spike.rockcc.dto.RegisterDto;
import cn.spike.rockcc.dto.UserDto;
import cn.spike.rockcc.errorenum.GlobalExceptionCode;
import cn.spike.rockcc.exception.BusinessException;
import cn.spike.rockcc.feignclient.LoginFeignClient;
import cn.spike.rockcc.mapper.UserAccountMapper;
import cn.spike.rockcc.mapper.UserBaseInfoMapper;
import cn.spike.rockcc.mapper.UserIntegralMapper;
import cn.spike.rockcc.mapper.UserMapper;
import cn.spike.rockcc.query.UserBaseInfoQuery;
import cn.spike.rockcc.result.JSONResult;
import cn.spike.rockcc.service.IUserService;
import cn.spike.rockcc.util.BitStatesUtils;
import cn.spike.rockcc.util.Md5Utils;
import cn.spike.rockcc.util.StrUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.spike.rockcc.errorenum.GlobalExceptionCode.*;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author spike
 * @since 2023-03-07
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LoginFeignClient loginFeignClient;

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private UserBaseInfoMapper userBaseInfoMapper;

    @Autowired
    private UserIntegralMapper userIntegralMapper;


    @Override
    public UserDto getInfo(Long id) {
        UserBaseInfo userBaseInfo = userBaseInfoMapper.selectById(id);
        userBaseInfo.setGrowScoreName(getGrowScoreName(userBaseInfo));
        User user = userMapper.selectById(id);
        UserIntegral userIntegral = userIntegralMapper.selectById(id);
        return new UserDto(user, userBaseInfo, userIntegral);
    }


    /**
     * 手机号注册流程
     *
     * @param dto
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = {Exception.class})
    public JSONResult register(RegisterDto dto) {
        //校验手机短信是否正确
        checkPhoneCode(dto);
        //添加login对象
        Login login = insertLogin(dto);
        //添加user对象到数据库
        User user = loginToUser(login);
        userMapper.insert(user);
        //将account和baseinfo对象添加到数据库
        UserAccount userAccount = userToUserAccount(user);
        UserBaseInfo userBaseInfo = userToUserBaseInfo(user, dto);
        userAccountMapper.insert(userAccount);
        //增送积分判断 - 赠送推荐人积分 - 改变推荐码状态 - 增加推荐人积分和成长值 - 设置注册用户baseionfo推荐人id - 添加baseinfo数据
        giveIntegral(dto.getInvitationCode(),userBaseInfo);
        //创建并添加新用户的积分表
        creatUserIntegral(user);
        return JSONResult.success();
    }

    /**
     * 赠送积分和成长值 - 并保存推荐人和注册用户的推荐关系
     * @param dto
     */
    private void giveIntegral(String invitationCode,UserBaseInfo userBaseInfo){
        if(invitationCode==null || invitationCode==""){
            userBaseInfoMapper.insert(userBaseInfo);
            return;
        }
        Wrapper<UserIntegral> wrapper = new EntityWrapper<>();
        wrapper.eq("invitation_code",invitationCode);
        List<UserIntegral> userIntegrals = userIntegralMapper.selectList(wrapper);
        if(userIntegrals==null || userIntegrals.size()==0)throw new BusinessException(INVITATION_CODE_EXCEPTION);
        Long referId = userIntegrals.get(0).getId();
        UserIntegral userIntegral = userIntegralMapper.selectById(referId);
        if(userIntegral.getSate()==1)throw new BusinessException(INVITATION_CODE_USED);
        userIntegral.setIntegral(userIntegral.getIntegral()+10);
        userIntegral.setSate(1);
        userIntegralMapper.updateById(userIntegral);
        userBaseInfo.setReferId(referId);
        userBaseInfoMapper.insert(userBaseInfo);

        UserBaseInfo referUserBaseInfo = userBaseInfoMapper.selectById(referId);
        referUserBaseInfo.setGrowScore(referUserBaseInfo.getGrowScore()+10);
        userBaseInfoMapper.updateById(referUserBaseInfo);
    }

    /**
     * 生成积分表数据
     */
    private void creatUserIntegral(User user){
        UserIntegral userIntegral = new UserIntegral();
        userIntegral.setId(user.getId());
        userIntegral.setIntegral(0);
        List<UserIntegral> userIntegrals = new ArrayList<>();
        String invitation_code = "";
        do{
            invitation_code = StrUtils.getComplexRandomString(4);
            Wrapper<UserIntegral> wrapper = new EntityWrapper<>();
            wrapper.eq("invitation_code",invitation_code);
            userIntegrals = userIntegralMapper.selectList(wrapper);
        }while (userIntegrals.size()!=0);
        userIntegral.setInvitationCode(invitation_code);
        userIntegral.setSate(0);
        userIntegralMapper.insert(userIntegral);
    }


    /**
     * 将login添加到数据库
     *
     * @param dto
     * @return
     */
    private Login insertLogin(RegisterDto dto) {
        Login login = registerDtoToLogin(dto);
        JSONResult jsonResult = loginFeignClient.register(login);
        if (!jsonResult.isSuccess()) throw new BusinessException(UAA_EXCEPTION);
        Object loginId = jsonResult.getData();
        login.setId(Long.parseLong(loginId.toString()));
        return login;
    }


    /**
     * 检查短信验证码
     *
     * @param dto
     */
    private void checkPhoneCode(RegisterDto dto) {
        Object phoneCode = redisTemplate.opsForValue().get("register:" + dto.getMobile());
        if (phoneCode == null) throw new BusinessException(PHONECODE_TIMEOUT_EXCEPTION);
        if (!phoneCode.toString().split(":")[0].equals(dto.getSmsCode()))
            throw new BusinessException(PHONECODE_FALSE_EXCEPTION);
    }


    /**
     * 将User对象转换为UserBaseInfo对象
     *
     * @param user
     * @return
     */
    private UserBaseInfo userToUserBaseInfo(User user, RegisterDto dto) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setCreateTime(user.getCreateTime());
        userBaseInfo.setUpdateTime(user.getCreateTime());
        userBaseInfo.setRegChannel(dto.getRegChannel());
        userBaseInfo.setGrowScore(0);
        userBaseInfo.setId(user.getId());
        return userBaseInfo;
    }

    /**
     * 将User对象转换为UserAccount对象
     *
     * @param user
     * @return
     */
    private UserAccount userToUserAccount(User user) {
        UserAccount userAccount = new UserAccount();
        userAccount.setCreateTime(user.getCreateTime());
        userAccount.setUsableAmount(new BigDecimal(0));
        userAccount.setFrozenAmount(new BigDecimal(0));
        userAccount.setId(user.getId());
        return userAccount;
    }

    /**
     * 将Login对象转换为User对象
     *
     * @param login
     * @return
     */
    private User loginToUser(Login login) {
        User user = new User();
        user.setPhone(login.getUsername());
        user.setNickName(login.getUsername());
        user.setLoginId(login.getId());
        user.setUpdateTime(user.getCreateTime());

        long state = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        state = BitStatesUtils.addState(state, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(state);

        return user;
    }

    /**
     * 将注册数据转换为Login对象
     *
     * @param dto
     * @return
     */
    private Login registerDtoToLogin(RegisterDto dto) {
        Login login = new Login();
        String password = dto.getPassword();
        String salt = StrUtils.getComplexRandomString(32);
        password = Md5Utils.encrypByMd5(password + salt);
        login.setPassword(password);
        login.setUsername(dto.getMobile());
        login.setType(Login.LOGIN_WEB);
        login.setEnabled(true);
        return login;
    }

    @Override
    public User loadByPhone(String phone) {
        return userMapper.loadByPhone(phone);
    }

    private String getGrowScoreName(UserBaseInfo userBaseInfo) {
        Integer growScore = userBaseInfo.getGrowScore();
        if (growScore > 0 && growScore < 99) return "青铜";
        else if (growScore > 100 && growScore < 299) return "白银";
        else if (growScore > 300 && growScore < 599) return "黄金";
        else if (growScore > 600 && growScore < 999) return "白金";
        else if (growScore > 1000 && growScore < 1499) return "钻石";
        else if (growScore > 1500 && growScore < 2499) return "大师";
        else if (growScore > 2500) return "王者";
        else return "零分！！";
    }
}
